package com.rupertjones.globalcron.web;

import com.rupertjones.globalcron.domain.Role;
import com.rupertjones.globalcron.domain.Setting;
import com.rupertjones.globalcron.domain.SettingType;
import com.rupertjones.globalcron.domain.User;
import net.sourceforge.stripes.action.Before;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.HandlesEvent;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.SimpleError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrors;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.access.prepost.PreAuthorize;

import java.util.ArrayList;
import java.util.Collection;

/**
 * <p>&copy Rupert Jones 2011,2012</p>
 *
 * @author rup
 */
public class EditUserAction extends AbstractFormAction {

    @ValidateNestedProperties({
        @Validate(field = "fullName", required = true, on = { "SaveOrUpdate" }),
        @Validate(field = "password", required = false, on = { "SaveOrUpdate" }),
        @Validate(field = "confirmPassword", required = false, on = { "SaveOrUpdate" })
    })
    private FormUser formUser;

    private User actualUser;

    private Setting passwordPolicy;

    @Before(stages = LifecycleStage.BindingAndValidation)
    public void loadAndBind() {
        String id = getContext().getRequest().getParameter("user.id");
        int userId = Integer.parseInt(id);
        actualUser = getUserService().findUser(userId);

        passwordPolicy = getSettingsService().find(SettingType.PASSWORD_POLICY);
        formUser = new FormUser(passwordPolicy);
        formUser.setFullName(actualUser.getFullName());
        formUser.setUsername(actualUser.getUsername());

        formUser.clearRoles();

        for(Role role : getRoles()) {
            FormRole formRole = new FormRole();
            formRole.setName(role.getName());
            formRole.setAssigned(actualUser.hasRole(role));
            formUser.addRole(formRole);
        }
    }

    @DefaultHandler
    public Resolution view() {
        return new ForwardResolution("/WEB-INF/jsp/edit_user.jsp");
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @HandlesEvent("SaveOrUpdate")
    public Resolution onSave() {
        formUser.unassignRoles();
        for(int index = 0; index < getRoles().size(); index++) {
            String value = getContext().getRequest().getParameter(String.format("%s_%s", "roles", String.valueOf(index)));
            if(value != null) {
                formUser.getRole(value).setAssigned(true);
            }
        }

        ValidationErrors passwordError = new ValidationErrors();

        if(formUser.hasPassword()) {
            boolean passwordMatch = this.formUser.isPasswordMatch();
            boolean compliant = this.formUser.isPasswordPolicyCompliant();

            if(!passwordMatch) {
                passwordError.add("password", new LocalizableError("password.nomatch"));
            }

            if(!compliant) {
                passwordError.add("password", new SimpleError(passwordPolicy.getDescription()));
            }
        }

        if (passwordError.size() == 0) {
            actualUser.setFullName(this.formUser.getFullName());
            actualUser.clearRoles();

            for(FormRole role : formUser.getRoles())  {
                if(role.isAssigned()) {
                    actualUser.addRole(getUserService().findRole(role.getName()));
                }
            }

            if(formUser.hasPassword()) {
                getUserService().saveWithPassword(actualUser, this.formUser.getPassword());
            } else {
                getUserService().save(actualUser);
            }
            return new ForwardResolution("InfoUsers.action");
        } else {
            getContext().setValidationErrors(passwordError);
            return getContext().getSourcePageResolution();
        }
    }

    public FormUser getUser() {
        return formUser;
    }

    private Collection<Role> getRoles() {
        return getUserService().findAllRoles();
    }
}
